#include "File/YamlLoader.h"
#include "Functions/String.h"
#include "Functions/TerminalIO.h"
#include "RooMsgService.h"
#include "TError.h"
#include "TStyle.h"
#include <string>
using namespace BOSS_Afterburner;
using namespace BOSS_Afterburner::String;
using namespace BOSS_Afterburner::TerminalIO;
using namespace YAML;
using namespace std;

std::vector<TString> YamlLoader::fLoadedPaths;
std::vector<TString> YamlLoader::fLoadedConfigs;

YamlLoader::YamlLoader(const TString& path) try : fPath(path),
                                                  fName(NoExtension(NoMainDir(path))),
                                                  Node(YAML::LoadFile(path.Data()))
{
  SetIoSettings(*this);
  if(!(*this)["Settings"]) return;
  fLoadedPaths.push_back(fPath);
  fLoadedConfigs.push_back(fName);
}
catch(const YAML::BadFile& e)
{
  PrintFatalError(Form("Configuration file \"%s\" does not exist", path.Data()));
}

void YamlLoader::SetIoSettings(const YAML::Node& input)
{
  const auto& settings = input["Settings"];
  if(!settings) return;

  SetStatLegend(settings);
  SetRooFitOutputLevel(settings);
  SetRootOutputLevel(settings);
  SetCanvasTitle(settings);
}

void YamlLoader::SetStatLegend(const YAML::Node& input)
{
  const auto& stats = input["Plot legend with statistics"];
  if(!stats) return;
  gStyle->SetOptStat(stats.as<bool>());
}

void YamlLoader::SetRooFitOutputLevel(const YAML::Node& input)
{
  const auto& roofit = input["RooFit output message level"];
  if(!roofit) return;
  const auto setting = roofit.as<string>();
  if(setting.compare("DEBUG") == 0)
    SetRooFitOutputLevel_helper(RooFit::DEBUG);
  else if(setting.compare("INFO") == 0)
    SetRooFitOutputLevel_helper(RooFit::INFO);
  else if(setting.compare("PROGRESS") == 0)
    SetRooFitOutputLevel_helper(RooFit::PROGRESS);
  else if(setting.compare("WARNING") == 0)
    SetRooFitOutputLevel_helper(RooFit::WARNING);
  else if(setting.compare("ERROR") == 0)
    SetRooFitOutputLevel_helper(RooFit::ERROR);
  else if(setting.compare("FATAL") == 0)
    SetRooFitOutputLevel_helper(RooFit::FATAL);
}

void YamlLoader::SetRooFitOutputLevel_helper(RooFit::MsgLevel input)
{
  RooMsgService::instance().setGlobalKillBelow(input);
  switch(input)
  {
    case RooFit::DEBUG: RooFit::PrintLevel(-1); break;
    case RooFit::INFO: RooFit::PrintLevel(0); break;
    case RooFit::PROGRESS: RooFit::PrintLevel(1); break;
    case RooFit::WARNING: RooFit::PrintLevel(2); break;
    case RooFit::ERROR:
    case RooFit::FATAL:
      RooFit::Warnings(false);
      RooFit::PrintLevel(3);
      break;
  }
}

void YamlLoader::SetRootOutputLevel(const YAML::Node& input)
{
  const auto& root = input["ROOT output message level"];
  if(!root) return;
  gErrorIgnoreLevel = root.as<Int_t>();
}

void YamlLoader::SetCanvasTitle(const YAML::Node& input)
{
  const auto& title = input["Canvas title"];
  if(!title) return;
  gStyle->SetOptTitle(title.as<Bool_t>());
}